﻿using log4net;
using System;
using System.Collections.Concurrent;
using System.Configuration;
using System.IO.Ports;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Server;

namespace SerialWebSocketBridge
{
    class Program
    {
        // 初始化log4net日志（全局唯一）
        private static readonly ILog _log = LogManager.GetLogger(typeof(Program));

        // 串口配置
        private static string _serialPortName;
        private static int BaudRate = 115200;
        private static SerialPort _serialPort;
        private static WebSocketServer _webSocketServer;

        // 线程安全锁与队列
        public static readonly object _serialLock = new object();
        private static readonly ConcurrentQueue<byte[]> _serialSendQueue = new ConcurrentQueue<byte[]>();
        private static bool _isProcessingQueue = false;

        static void Main(string[] args)
        {
            // 初始化log4net（读取配置文件）
            log4net.Config.XmlConfigurator.Configure();
            _log.Info("串口WebSocket中转程序启动...");
            Console.WriteLine("串口WebSocket中转程序启动...");
            //// 获取可用串口
            //string[] availablePorts = SerialPort.GetPortNames();
            //if (availablePorts.Length == 0)
            //{
            //    _log.Error("未发现可用串口，请检查设备连接");
            //    Console.WriteLine("未发现可用串口，请检查设备连接");
            //    _log.Info("按任意键退出...");
            //    Console.WriteLine("按任意键退出...");
            //    Console.ReadKey(); // 仅保留这处控制台输入（用于等待用户退出）
            //    return;
            //}

            //_serialPortName = availablePorts[0];
            _serialPortName = ConfigurationManager.AppSettings["ComPortName"];
            BaudRate = int.Parse(ConfigurationManager.AppSettings["BaudRate"]);
            //_log.Info($"发现可用串口: {string.Join(", ", availablePorts)}");
            _log.Info($"选择使用串口: {_serialPortName}，波特率: {BaudRate}");
            //Console.WriteLine($"发现可用串口: {string.Join(", ", availablePorts)}");
            Console.WriteLine($"选择使用串口: {_serialPortName}，波特率: {BaudRate}");

            // 初始化组件
            InitSerialPort();
            StartSerialSendWorker();
            InitWebSocketServer();

            _log.Info("服务已就绪，按ESC键退出程序");
            Console.WriteLine("服务已就绪，按ESC键退出程序");
            while (Console.ReadKey(true).Key != ConsoleKey.Escape)
            {
                Thread.Sleep(100);
            }

            // 清理资源
            CleanupResources();
            Console.WriteLine("程序已退出");
            _log.Info("程序已退出");
        }

        #region 核心方法（仅用log4net日志）
        private static void InitSerialPort()
        {
            _serialPort = new SerialPort(_serialPortName, BaudRate)
            {
                Parity = Parity.None,
                DataBits = 8,
                StopBits = StopBits.One,
                Handshake = Handshake.None,
                ReadTimeout = 1000,
                WriteTimeout = 1000,
                ReadBufferSize = 8192,
                WriteBufferSize = 8192
            };

            // 串口数据接收事件
            _serialPort.DataReceived += (sender, e) =>
            {
                try
                {
                    lock (_serialLock)
                    {
                        int bytesToRead = _serialPort.BytesToRead;
                        if (bytesToRead <= 0) return;

                        byte[] buffer = new byte[bytesToRead];
                        int actualRead = _serialPort.Read(buffer, 0, bytesToRead);
                        if (actualRead > 0)
                        {
                            SerialService.BroadcastToClient(buffer);
                            _log.Debug($"串口接收数据（长度: {actualRead}字节）: {BitConverter.ToString(buffer)}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Error($"串口数据处理错误: {ex.Message}");
                }
            };

            try
            {
                _serialPort.Open();
                _log.Info("串口已打开，等待数据...");
                Console.WriteLine("串口已打开，等待数据...");
            }
            catch (Exception ex)
            {
                _log.Error($"串口打开失败: {ex.Message}");
                Console.WriteLine($"串口打开失败: {ex.Message}");
                _log.Warn("请检查端口是否被占用后重试");
                Console.WriteLine("请检查端口是否被占用后重试");
                _log.Info("按任意键退出...");
                Console.WriteLine("按任意键退出...");
                Console.ReadKey(); // 仅保留退出等待
                Environment.Exit(1);
            }
        }

        private static void StartSerialSendWorker()
        {
            _isProcessingQueue = true;
            Thread sendThread = new Thread(() =>
            {
                while (_isProcessingQueue)
                {
                    if (_serialSendQueue.TryDequeue(out byte[] data)
                        && _serialPort != null
                        && _serialPort.IsOpen)
                    {
                        try
                        {
                            lock (_serialLock)
                            {
                                _serialPort.Write(data, 0, data.Length);
                            }
                            _log.Debug($"串口发送数据（长度: {data.Length}字节）: {BitConverter.ToString(data)}");
                        }
                        catch (Exception ex)
                        {
                            _log.Warn($"串口发送失败: {ex.Message}");
                        }
                    }
                    else
                    {
                        Thread.Sleep(1);
                    }
                }
            })
            {
                IsBackground = true,
                Name = "SerialSendWorker"
            };
            sendThread.Start();
            _log.Info("串口发送线程已启动");
            Console.WriteLine("串口发送线程已启动");
        }

        private static void InitWebSocketServer()
        {
            _webSocketServer = new WebSocketServer(8080);
            _webSocketServer.AddWebSocketService<SerialService>("/serial");
            _webSocketServer.Start();
            _log.Info("WebSocket服务器已启动，监听 ws://localhost:8080/serial");
            Console.WriteLine("WebSocket服务器已启动，监听 ws://localhost:8080/serial");
        }

        private static void CleanupResources()
        {
            _isProcessingQueue = false;
            _webSocketServer?.Stop();
            if (_serialPort != null)
            {
                if (_serialPort.IsOpen) _serialPort.Close();
                _serialPort.Dispose();
            }
            _log.Info("资源已清理（串口关闭、WebSocket服务停止）");
        }
        #endregion

        #region WebSocket服务类（使用log4net）
        public class SerialService : WebSocketBehavior
        {
            private static readonly ILog _serviceLog = LogManager.GetLogger(typeof(SerialService));
            private static SerialService _currentSession;

            protected override void OnOpen()
            {
                _currentSession = this;
                _serviceLog.Info("WebSocket客户端已连接");
            }

            protected override void OnMessage(MessageEventArgs e)
            {
                if (_serialPort != null && _serialPort.IsOpen && e.RawData != null && e.RawData.Length > 0)
                {
                    _serialSendQueue.Enqueue(e.RawData);
                    _serviceLog.Debug($"收到客户端数据（{e.Data}）（长度: {e.RawData.Length}字节）");
                }
            }

            protected override void OnClose(CloseEventArgs e)
            {
                if (_currentSession == this)
                {
                    _currentSession = null;
                    _serviceLog.Info($"WebSocket客户端已断开（原因: {e.Reason}）");
                }
            }

            protected override void OnError(WebSocketSharp.ErrorEventArgs e)
            {
                _serviceLog.Error($"WebSocket错误: {e.Message}");
            }

            public static void BroadcastToClient(byte[] data)
            {
                if (_currentSession != null && _currentSession.State == WebSocketState.Open)
                {
                    try
                    {
                        _currentSession.Send(data);
                        _serviceLog.Info($"向客户端转发数据（长度: {data.Length}字节）");
                    }
                    catch (Exception ex)
                    {
                        _serviceLog.Error($"向客户端转发失败: {ex.Message}");
                    }
                }
            }
            
            // 用于测试的模拟数据发送方法 - 真正模拟DataReceived事件处理流程
            public static void SimulateRapidButtonPresses(int pressCount = 2)
            {
                _serviceLog.Info($"开始模拟快速按钮按下测试，共{pressCount}次点击");
                
                for (int i = 1; i <= pressCount; i++)
                {
                    // 模拟按下信号
                    byte[] pressSignal = new byte[] { 0x01, (byte)i }; // 1表示按下，后跟序号
                    _serviceLog.Info($"模拟按钮按下 #{i}");
                    
                    // 模拟DataReceived事件处理流程，包括锁和异常处理
                    SimulateDataReceivedEvent(pressSignal, i, true);
                    
                    // 短暂延迟模拟真实按键间隔
                    Thread.Sleep(1);
                    
                    // 模拟弹起信号
                    byte[] releaseSignal = new byte[] { 0x00, (byte)i }; // 0表示弹起，后跟序号
                    _serviceLog.Info($"模拟按钮弹起 #{i}");
                    
                    // 模拟DataReceived事件处理流程，包括锁和异常处理
                    SimulateDataReceivedEvent(releaseSignal, i, false);
                    
                    // 短暂延迟
                    Thread.Sleep(1);
                }
                
                _serviceLog.Info("模拟测试完成，检查是否所有信号都被正确处理");
            }
            
            // 模拟DataReceived事件的完整处理流程
            private static void SimulateDataReceivedEvent(byte[] data, int sequence, bool isPress)
            {
                try
                {
                    // 完全模拟DataReceived事件中的锁操作
                    lock (_serialLock)
                    {
                        _serviceLog.Info($"[{sequence}] 进入DataReceived锁区域 ({(isPress ? "按下" : "弹起")})");
                        
                        // 模拟真实的数据处理
                        int dataLength = data.Length;
                        if (dataLength > 0)
                        {
                            // 这里完全按照DataReceived事件中的处理逻辑
                            BroadcastToClient(data);
                            _serviceLog.Info($"[{sequence}] 模拟数据已处理并转发给客户端（长度: {dataLength}字节）: {BitConverter.ToString(data)}");
                        }
                    }
                    _serviceLog.Debug($"[{sequence}] DataReceived事件处理完成 ({(isPress ? "按下" : "弹起")})");
                }
                catch (Exception ex)
                {
                    _serviceLog.Error($"[{sequence}] 模拟DataReceived事件处理错误: {ex.Message}");
                }
            }
        }
        #endregion
    }
}